package com.cicc.beergamevirtualsimulationsystem.aspect;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cicc.beergamevirtualsimulationsystem.annotation.SmsLimit;
import com.cicc.beergamevirtualsimulationsystem.common.errorEnum.LoginErrorEnum;
import com.cicc.beergamevirtualsimulationsystem.common.errorEnum.RegisterErrorEnum;
import com.cicc.beergamevirtualsimulationsystem.common.exception.BizException;
import com.cicc.beergamevirtualsimulationsystem.entity.LimitLogEntity;
import com.cicc.beergamevirtualsimulationsystem.service.LimitService;
import com.cicc.beergamevirtualsimulationsystem.service.LoginService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author 银角大王
 */
@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class RegisterLimitAspect {
    private final LimitService limitService;
    private final LoginService loginService;


    @Pointcut("execution(* com.cicc.beergamevirtualsimulationsystem.service.*.*(..)) && @annotation(com.cicc.beergamevirtualsimulationsystem.annotation.RegisterLimit)")
    public void pointCut(){}
    @Pointcut("execution(* com.cicc.beergamevirtualsimulationsystem.service.*.*(..)) && @annotation(com.cicc.beergamevirtualsimulationsystem.annotation.SmsLimit)")
    public void smsLimitPointCut(){}

    /**
     * 简单的注册限制检查
     * @param pjp
     */
//    @Around("pointCut()")
    public void registerLimit(ProceedingJoinPoint pjp) throws Throwable {

        // 先校验是否超过100次
        HttpServletRequest request = (HttpServletRequest) pjp.getArgs()[0];
        String ip = request.getRemoteAddr();
        // 先查询统计次数
        LambdaQueryWrapper<LimitLogEntity> wrapper = new LambdaQueryWrapper<LimitLogEntity>()
                .eq(LimitLogEntity::getIp, ip)
                .eq(LimitLogEntity::getType, "register")
                .eq(LimitLogEntity::getTime, LocalDate.now());
        LimitLogEntity limitLogEntity = limitService.getOne(wrapper);

        // 一天只能100次才能完成注册
        if(!Objects.isNull(limitLogEntity) &&limitLogEntity.getCount() >= 100){
            throw new BizException(LoginErrorEnum.LIMIT_ERROR.getCode(), LoginErrorEnum.LIMIT_ERROR.getDesc());
        }
        Object proceed = pjp.proceed();
        // 当天首次注册
        if(Objects.isNull(limitLogEntity) ){
            LimitLogEntity register = new LimitLogEntity();
            register.setIp(ip);
            register.setType("register");
            register.setTime(LocalDateTime.now());
            register.setCount(1);
            limitService.save(register);
            return;
        }
        // 更新次数
        LambdaUpdateWrapper<LimitLogEntity> updateWrapper = new LambdaUpdateWrapper<LimitLogEntity>()
                .set(LimitLogEntity::getCount, limitLogEntity.getCount() + 1)
                .eq(LimitLogEntity::getId, limitLogEntity.getId());
        limitService.update(updateWrapper);
    }


    /**
     * 手机号 +  ip限制
     */
    @Around("smsLimitPointCut()")
    public void phoneLimit(ProceedingJoinPoint pjp) throws Throwable {
        HttpServletRequest request = (HttpServletRequest) pjp.getArgs()[0];
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        SmsLimit annotation = signature.getMethod().getAnnotation(SmsLimit.class);
        String type = annotation.type();
        String phone = request.getParameter("phone");
        // 短信是否仍在有效期
        checkSmsExpire(phone);
        // 针对ip限制
        checkIpLimit(request.getRemoteAddr(),type);
        // 针对当前手机号
        LimitLogEntity limitLogEntity = checkPhoneLimit(phone,type);

        Object proceed = pjp.proceed();
        // 没有发过
        if(Objects.isNull(limitLogEntity)){
            LimitLogEntity register = new LimitLogEntity();
            register.setIp(request.getRemoteAddr());
            register.setType(type);
            register.setPhone(phone);
            register.setTime(LocalDateTime.now());
            register.setCount(1);
            limitService.save(register);
            return;
        }
        // 更新次数 发送次数小于10次
        LambdaUpdateWrapper<LimitLogEntity> updateWrapper = new LambdaUpdateWrapper<LimitLogEntity>()
                .set(LimitLogEntity::getCount, limitLogEntity.getCount() + 1)
                .set(LimitLogEntity::getTime, LocalDateTime.now())
                .eq(LimitLogEntity::getId, limitLogEntity.getId());
        limitService.update(updateWrapper);
    }
    private void checkSmsExpire(String phone) {
        LocalDateTime endTime = loginService.getSmsEndTime(phone);
        if(Objects.nonNull(endTime) && endTime.isAfter(LocalDateTime.now())){
            throw new BizException(RegisterErrorEnum.CAPTCHA_NOT_EXPIRE.getCode(), RegisterErrorEnum.CAPTCHA_NOT_EXPIRE.getDesc());
        }
    }
    private void checkIpLimit(String ip,String type) {
        // ip限制 1 分钟一条   没发过 或者 已经过期
        LambdaQueryWrapper<LimitLogEntity> wrapper = new LambdaQueryWrapper<LimitLogEntity>()
                .eq(LimitLogEntity::getIp, ip)
                .eq(LimitLogEntity::getType, type)
                .between(
                        LimitLogEntity::getTime,
                        // 当天开始时间 (00:00:00)
                        LocalDate.now().atStartOfDay(),
                        // 当天结束时间 (23:59:59.999)
                        LocalDate.now().atTime(LocalTime.MAX)
                ).orderByDesc(LimitLogEntity::getTime);

        List<LimitLogEntity> limitLogEntities = limitService.list(wrapper);
        // 当前ip没发过短信
        if(Objects.isNull(limitLogEntities) || limitLogEntities.isEmpty()){
            return;
        }
        // 针对当前ip:判断发送时间是否在一分钟之内
        if(limitLogEntities.get(0).getTime().isAfter(LocalDateTime.now().minusMinutes(1))){
            throw new BizException(RegisterErrorEnum.SMS_SENT_RATE_LIMIT_ERROR.getCode(), RegisterErrorEnum.SMS_SENT_RATE_LIMIT_ERROR.getDesc());
        }
    }
    private LimitLogEntity checkPhoneLimit(String phone,String type) {

        LambdaQueryWrapper<LimitLogEntity> wrapper = new LambdaQueryWrapper<LimitLogEntity>()
                .eq(LimitLogEntity::getPhone, phone)
                .eq(LimitLogEntity::getType, type)
                .between(
                        LimitLogEntity::getTime,
                        // 当天开始时间 (00:00:00)
                        LocalDate.now().atStartOfDay(),
                        // 当天结束时间 (23:59:59.999)
                        LocalDate.now().atTime(LocalTime.MAX)
                );
        LimitLogEntity limitLogEntity = limitService.getOne(wrapper);
        if(Objects.nonNull(limitLogEntity) && limitLogEntity.getCount() >= 10){
            throw new BizException(RegisterErrorEnum.PHONE_LIMIT_ERROR.getCode(), RegisterErrorEnum.PHONE_LIMIT_ERROR.getDesc());
        }
        // 没有发过 或者发送次数小于10次
        return limitLogEntity;
    }
}
